package net.linlan.plat.comm.utils;

import net.linlan.commons.core.StringUtils;
import net.linlan.frame.FrameToken;
import net.linlan.plat.comm.service.AuthService;
import net.linlan.utils.crypt.RSAUtil;
import net.linlan.utils.http.HttpContextUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

public class AuthReqUtils {
    /**
     * 用户敏感信息对象，对用户敏感信息进行缓存处理使用的KEY，缓存10分钟
     */
    public static final String REDIS_BASE_USER_KEY = "llauth:base_user:";
    /**
     * 会员应用用户对象，对会员信息进行缓存处理使用的KEY，缓存10分钟
     */
    public static final String REDIS_FRAME_USER_KEY = "llauth:frame_user:";
    /**
     * 公开市民用户，用市民对象进行缓存处理使用的KEY，缓存10分钟
     */
    public static final String REDIS_PUB_CITIZEN_KEY = "llauth:pub_citizen:";
    /**
     * 平台用户的ID，对平台信息（前台工程访问信息）进行缓存处理使用的KEY，缓存10分钟
     */
    public static final String REDIS_ACCOUNT_KEY = "llauth:member_account:";
    /**
     * 站点的ID，对站点信息进行缓存处理使用的KEY，缓存10分钟
     */
    public static final String REDIS_SITE_KEY = "llauth:manage_site:";
    /**
     * 验证码，临时redis缓存路径，缓存3分钟
     */
    public static final String REDIS_VERIFY_KEY = "llauth:verify_code:";
    /**
     * 外部平台的账户对象，缓存1天
     */
    public static final String REDIS_BACK_OUT_ACCOUNT ="llauth:out_account:";
    /**
     * 单点登录SSO用户信息，缓存30分钟
     */
    public static final String REDIS_SSO_USER_KEY = "llauth:sso_user:";

    /**
     * 后台使用的会员ID的key，放入request内
     */
    public static final String REQUEST_BACK_MEMBER_ID = "_member_id";
    /**
     * 用户会员对象，用于REQUEST内进行会员用户基本信息传递使用
     */
    public static final String REQUEST_BACK_MEMBER_USER = "_member_user";
    /**
     * 权限Key
     */
    public static final String REQUEST_BACK_PERMISSION_MODEL = "_permissionKey";

    /**
     * 后台使用的平台ID的key，放入request内，前台会在header内放入此信息
     */
    public static final String REQUEST_FRONT_ACCOUNT_ID = "member-account-id";

    /**
     * AES加密参数
     */
    public static final String REQUEST_FRONT_AES_KEY = "aes-key";
    /**
     * AES加密IV参数
     */
    public static final String REQUEST_FRONT_AES_IV = "aes-iv";
    /**
     * AES加密IV键值参数
     */
    public static final String REQUEST_FRONT_AES_IV_KEY = "aes-iv-key";

    /**
     * 存放在request内的用户认证令牌标识
     */
    public static final String TOKEN_KEY = "token";
    /**
     * 存放前台进入的平台source来源，如smy，wechat，alipay
     */
    public static final String SOURCE_KEY = "source";
    /**
     * 内部登录accountId前缀或必须包含信息
     */
    public static final String DEFAULT_INNER_PREFIX = "ll";
    /**
     * 默认平台代码前缀，提供给前台外部使用的THIRD前缀
     */
    public static final String DEFAULT_THIRD_PREFIX = "ll_third";
    /**
     * 单点登录accountId前缀或必须包含信息
     */
    public static final String DEFAULT_SSO_PREFIX = "ll_sso";

    /**
     * 文章资讯栏目缓存前缀，详情直接加id，列表则列表查询条件动态拼接
     */
    public static final String REDIS_CHANNEL_KEY = "llauth:channel:";
    /**
     * 文章资讯缓存前缀，详情直接加id，列表则列表查询条件动态拼接
     */
    public static final String REDIS_CONTENT_KEY = "llauth:content:";
    /**
     * 组织机构缓存前缀，详情直接加id，列表则列表查询条件动态拼接
     */
    public static final String REDIS_ORGAN_KEY = "llauth:organ:";
    /**
     * 人员缓存前缀，详情直接加id，列表则列表查询条件动态拼接
     */
    public static final String REDIS_USER_KEY = "llauth:user:";
    /**
     * 指标缓存前缀，详情直接加id，列表则列表查询条件动态拼接
     */
    public static final String REDIS_QUOTA_KEY = "llauth:quota:";

    private static String tokenPrivateKey = "";

    @Autowired
    private AuthService authService;

    /** 从request内获取token内容，首先从header内解析，如果没有再从parameter内解析
     * @param request 请求
     * @return token
     */
    public static String getToken(HttpServletRequest request) {
        //从header中获取token
        String token = request.getHeader(TOKEN_KEY);
        //如果header中不存在token，则从参数中获取token, 存在风险，注释从参数获取token方法
        if(StringUtils.isBlank(token)){
            token = request.getParameter(TOKEN_KEY);
        }
        //导出时需要token,参数校验格式：token+时间戳 逗号,隔开;校验时效性2分钟
        String permissionKey = request.getParameter(REQUEST_BACK_PERMISSION_MODEL);

        if(StringUtils.isNotBlank(permissionKey)){
            try {
                //add by linlan decode一次，前端可能Encode过了
                permissionKey = URLDecoder.decode(permissionKey, StandardCharsets.UTF_8.name());
                permissionKey = permissionKey.replaceAll(" ","+");
                //end
                //permissionKey= permissionKey.replace(" ","+");
                String permissionKeyStr = RSAUtil.decrypt(permissionKey, RSAUtil.getPrivateKey(tokenPrivateKey));
                String[] split = permissionKeyStr.split(",");
                //add by linlan on 2022年6月10日22点08分，只有token的不让过
                if(split.length==1){
                    return null;
                }
                //end
                token = split[0];
                String time = split[1];
                //校验时效性,两分钟内有效
                long currTime = System.currentTimeMillis();
                if(currTime-Long.valueOf(time) > 2*60*1000){
                    return null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (StringUtils.isBlank(token)){
            return null;
        } else {
            return token;
        }
    }

    public static Long getMemberId(HttpServletRequest request) {
        Long memberId = (Long) request.getAttribute(REQUEST_BACK_MEMBER_ID);
        if (memberId != null){
            return memberId;
        }
        return null;
    }

    public static void setMemberId(HttpServletRequest request, Long memberId) {
        request.setAttribute(REQUEST_BACK_MEMBER_ID, memberId);
    }

    /**
     * 获取session
     * @return session对象
     */
    public static HttpSession getSession(){
        //获取request
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        return request.getSession();
    }

    /** 从request内获取key内容，首先从header内解析，如果没有再从parameter内解析
     * @param request 请求
     * @param key 键
     * @return 通过key获取request内的参数
     */
    public static String getByKey(HttpServletRequest request, String key) {
        //从header中获取具体key值，可以为token，platId等
        String inputValue = request.getHeader(key);
        //如果header中不存在，则从参数中获取具体key值，可以为token，platId等
        if(StringUtils.isBlank(inputValue)){
            inputValue = request.getParameter(key);
        }
        //如果值为空，则反馈null
        if (StringUtils.isBlank(inputValue)){
            return null;
        } else {
            return inputValue;
        }
    }

    public static void setByKey(HttpServletRequest request, String key, String value) {
        request.setAttribute(key, value);
    }


    /** 针对2分钟内访问邮箱的模式处理，从URL路径中提前permissionKey，获取token，验证时间戳
     * 区分之前的getToken方法，不从Header里面取，名称修改为：getTokenFromEncryptUrl
     * @param permissionKey 权限key
     * @return 解密后获取token
     */
    public static String getTokenFromEncryptUrl(String permissionKey) {
        //导出时需要token,参数校验格式：token+时间戳 逗号,隔开;校验时效性2分钟
        String token="";
        if(StringUtils.isNotBlank(permissionKey)){
            try {
                //permissionKey= permissionKey.replace(" ","+");
                String permissionKeyStr = RSAUtil.decrypt(permissionKey, RSAUtil.getPrivateKey(tokenPrivateKey));
                String[] split = permissionKeyStr.split(",");
                token = split[0];
                String time = split[1];
                //校验时效性,两分钟内有效
                long currTime = System.currentTimeMillis();
                if(currTime-Long.valueOf(time) > 120*1000){
                    return "";
                }else{
                    return token;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return token;
    }

    public  Boolean checkTokenExpire(String token){
        if(StringUtils.isEmpty(token)){
            return false;
        }
        //查询token信息
        FrameToken memberToken = authService.getByToken(token);
        if (memberToken == null || memberToken.getExpireTime().getTime() < System.currentTimeMillis()) {
            return false;
        }else{
            return true;
        }
    }


    /** 通过request获取header内的token字符串
     * @param prefix 传入的accountId前缀，如ll，ioc
     * @return token字符串
     */
    public static String getAccountIdToken(String prefix){
        //从request中获取token, token为用户的clientSecret
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        String accountId = AuthReqUtils.getByKey(request, REQUEST_FRONT_ACCOUNT_ID);
        if (StringUtils.isNotBlank(accountId) && StringUtils.isNotBlank(prefix)) {
            if (accountId.contains(prefix)){
                return AuthReqUtils.getToken(request);
            }
        }
        return null;
    }

}
